package calculadora;

import exceptions.OperandException;

public class LogiCalculator {

	/**
	 * @param args
	 */

	private boolean memory; 
	private boolean p;
	private boolean q;
	private boolean isMemoryTrash;
	//private boolean isSecondOperand;
	private boolean isGoodResult;
	private int state;
	private int operator;
/*
 * 
 * constructor 
 */
	public LogiCalculator (){
		memory=false;
		isGoodResult=false;
		//isSecondOperand=false;
		isMemoryTrash=true;
		state=0;
	}
	/*
	 * Getters and Setters
	 */
	public boolean isGoodResult() {
		return isGoodResult;
	}
	public void setGoodResult(boolean isGoodResult) {
		this.isGoodResult = isGoodResult;
	}
	public boolean isMemory() {
		return memory;
	}
	public void setMemory(boolean memory) {
		this.memory = memory;
	}
	public boolean getMemory (){
		return memory;
	}
	public boolean isP() {
		return p;
	}
	public void setP(boolean p) {
		setState(STATE.AWAITING_OPERATION);
		this.p = p;
	}
	public boolean isQ() {
		return q;
	}
	public void setQ(boolean q) {
		setState(STATE.AWAITING_ENTER);
		this.q = q;
	}
	public boolean isMemoryTrash() {
		return isMemoryTrash;
	}
	public void setMemoryTrash(boolean isMemoryTrash) {
		this.isMemoryTrash = isMemoryTrash;
	}
//	public boolean isSecondOperand() {
//		return isSecondOperand;
//	}
//	public void setSecondOperand(boolean isSecondOperand) {
//		this.isSecondOperand = isSecondOperand;
//	}
	public int getState() {
		return state;
	}
	public void setState(int state) {
		this.state = state;
	}
	/*
	 * methods
	 */
	public void  logicalNOT ()throws OperandException{
		p = !p;
	}
	private void logicalOR()throws OperandException{
		if (getState()==STATE.AWAITING_ENTER){

			p = p|q;
		}
		else{
			throw new OperandException ("MISSING OPERAND ERROR");
		}
	}
	private void logicalAND()throws OperandException{
		if (getState()==STATE.AWAITING_ENTER){

			p = p&q;

		}
		else{
			throw new OperandException ("MISSING OPERAND ERROR");
		}
	}
	private void logicalTHEN ()throws OperandException{
		if (getState()==STATE.AWAITING_ENTER){

			p = (!p)|q;

		}
		else{
			throw new OperandException ("MISSING OPERAND ERROR");
		}
	}
	private void logicalXOR ()throws OperandException{
		if (getState()==STATE.AWAITING_ENTER){

			p = p^q;

		}
		else{
			throw new OperandException ("MISSING OPERAND ERROR");
		}
	}
	private void logicalNOR ()throws OperandException{
		if (getState()==STATE.AWAITING_ENTER){


			p = !(p|q);

		}
		else{
			throw new OperandException ("MISSING OPERAND ERROR");
		}
	}


	private void logicalNAND ()throws OperandException {
		if (getState()==STATE.AWAITING_ENTER){



			p = !(p&q);

		}
		else{
			throw new OperandException ("MISSING OPERAND ERROR");
		}
	}

	private void logicalNXOR ()throws OperandException{
		if (getState()==STATE.AWAITING_ENTER){

			p = !(p^q);
		}
		else{
			throw new OperandException ("MISSING OPERAND ERROR");
		}
	}

	public void sendOperation (int op)throws OperandException{
		
		
		switch (op) {

		case OPERATION.CLEAR:
			setState(STATE.INIT);
			setGoodResult(false);
			
			break;
		case OPERATION.MEMORY:
			if(isMemoryTrash)
				throw new OperandException ("memory is empty");

			switch (getState()){
			case STATE.AWAITING_ENTER:
				q=memory;
				break;
			case STATE.INIT:
				p=memory;
				setState(state++);
				break;
			case STATE.AWAITING_OPERATION:
				setState(state--);
				break;
			}
			break;
		case OPERATION.XOR:
		case OPERATION.NAND:
		case OPERATION.NOR:
		case OPERATION.NXOR:
		case OPERATION.OR:
		case OPERATION.THEN:
		case OPERATION.AND:
			
			switch(getState()){
			case STATE.INIT:
				
//				setState(STATE.AWAITING_OPERAND);
//				setState(STATE.AWAITING_OPERAND);
//				System.out.println("got first operand");
				
				break;
			case STATE.AWAITING_OPERATION:
			case STATE.OPERATION_DONE:
				setState(STATE.AWAITING_OPERAND);
				operator=op;
				System.out.println("got operation, awaiting second operand");
				break;
//			case STATE.AWAITING_OPERAND:
//				setState(STATE.AWAITING_ENTER);
//				System.out.println("awaiting enter");
//				break;
			case STATE.AWAITING_ENTER:
				doOperation(operator);
				operator=op;
				
				break;
				
			
			default:
				throw new exceptions.OperandException ("ERROR");
			}
	
			break;
		case OPERATION.ENTER:
			if (getState()==STATE.AWAITING_ENTER){
				doOperation(operator);
				if (getState()==STATE.OPERATION_DONE){
					System.out.println("operation done");
					setGoodResult(true);
					
				}
				
			}
			break;
			
		default:
			throw new exceptions.OperandException ("Machine State ERROR");
		}
	}

	public boolean getP() {
		
		return p;
	}
public void sendOperation (String operation)throws OperandException{
	System.out.println(operation);
}
private void doOperation (int op) throws OperandException{
	try{
	switch (op) {
	case OPERATION.XOR:
		logicalXOR();
		break;
	case OPERATION.NAND:
		logicalNAND();
		break;
	case OPERATION.NOR:
		logicalNOR();
		break;
	case OPERATION.NXOR:
		logicalNXOR();
		break;
	case OPERATION.OR:
		logicalOR();
		break;
	case OPERATION.THEN:
		logicalTHEN();
		break;
	case OPERATION.AND:
		logicalAND();
		break;

	default:
		new exceptions.OperandException ("doOperationError");
		break;
	}
	}catch (OperandException e){
		throw e;
	}
	setState(STATE.OPERATION_DONE);
}
}
